using System.ComponentModel;
using System.Configuration;
using System.Reflection;
using Needle.Utils;
using Cfg = System.Configuration.Configuration;

namespace Needle.Core.Configuration {
    /// <summary>
    /// The needle configuration section.
    /// </summary>
    [Description("The needle configuration section")]
    public class NeedleConfiguration : ConfigurationSection {
        /// <summary>
        /// The default name of a needle configuration section.
        /// </summary>
        public static readonly string DefaultSectionName;
        /// <summary>
        /// The default filename of a needle configuration section.
        /// </summary>
        public static readonly string DefaultFileName;

        static NeedleConfiguration() {
            DefaultSectionName = Strings.LowerCaseFirstChar(Assembly.GetExecutingAssembly().GetName().Name);
            DefaultFileName = DefaultSectionName + ".config";
        }

        #region Load and Save

        /// <summary>
        /// Gets the needle configuration section from the configuration.
        /// </summary>
        public static NeedleConfiguration Get(Cfg configuration,string sectionName) {
            Ensure.NotNull(configuration, "configuration");
            ConfigurationSection section = configuration.GetSection(sectionName);
            if (section == null) {
                NeedleConfiguration needleCfg = new NeedleConfiguration();
                needleCfg.appConfig = configuration;
                configuration.Sections.Add(sectionName, needleCfg);
                return needleCfg;
            } else {
                if (section is NeedleConfiguration) {
                    NeedleConfiguration needleCfg = (NeedleConfiguration)section;
                    needleCfg.appConfig = configuration;
                    return needleCfg;
                } else {
                    throw new ConfigurationErrorsException(
                        DefaultSectionName
                        + " section is not of the expected type '"
                        + typeof(NeedleConfiguration).AssemblyQualifiedName
                        + "' but of type '"
                        + section.GetType().AssemblyQualifiedName + "'");
                }
            }
        }

        /// <summary>
        /// Loads the configuration from the app.config
        /// </summary>
        /// <returns></returns>
        public static NeedleConfiguration Load() {
            Cfg cfg = LoadConfiguration();
            return Get(cfg, DefaultSectionName);
        }
        /// <summary>
        /// Saves the configuration to the default filename.
        /// </summary>
        public void Save() {
            appConfig.Save(ConfigurationSaveMode.Minimal);
        }
        /// <summary>
        /// save the configuration. 
        /// </summary>
        /// <param name="filePath">filePath must be relative to the app.config folder</param>
        public void Save(string filePath) {
            appConfig.SaveAs(filePath, ConfigurationSaveMode.Minimal);
        }

        private static Cfg LoadConfiguration() {
            return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        }

        #endregion

        #region fields

        private Cfg appConfig;

        #endregion

        #region constructor

        /// <summary>
        /// Creates a new instance
        /// </summary>
        public NeedleConfiguration() {
        }

        #endregion

        #region Configuration properties

        /// <summary>
        /// The kernel configuration settings.
        /// </summary>
        [ConfigurationProperty(Element.Settings, IsRequired = true)]
        [Description("The kernel configuration settings.")]
        public KernelSettingsElement Settings
        {
            get { return (KernelSettingsElement)this[Element.Settings]; }
            set { this[Element.Settings] = value; }
        }

        /// <summary>
        /// The root container.
        /// </summary>
        [ConfigurationProperty(Element.RootContext, IsRequired = true)]
        [Description("The root container.")]
        public ContextElement RootContext
        {
            get { return (ContextElement)this[Element.RootContext]; }
            set { this[Element.RootContext] = value; }
        }

        #endregion

    }

}
